#pragma once
#include "../commom/net.hpp"
#include "../commom/message.hpp"
#include <set>
namespace rpc
{
    namespace server
    {
        class ProvideManager
        {
        public:
            using ptr = std::shared_ptr<ProvideManager>;
            struct Provider
            {
                using ptr = std::shared_ptr<Provider>;
                BaseConnection::ptr conn;
                std::mutex _mutex;
                Address host;
                std::vector<std::string> methods;
                Provider(const BaseConnection::ptr &c, const Address &h) : conn(c), host(h) {}
                void appendMethod(const std::string &method)
                {
                    std::unique_lock<std::mutex> lock(_mutex);
                    methods.emplace_back(method);
                }
            };
        // 当一个新的服务提供者进行服务注册的时候调用
        Provider::ptr addProvider(const BaseConnection::ptr &c, const Address &h, const std::string &method){
        Provider::ptr provider;
        // 查找连接所关联的服务提供者对象，找到则获取，找不到就创建，并建立关联
        {
            std::unique_lock<std::mutex> lock(_mutex);
            auto it = _conns.find(c);
            if (it != _conns.end())
            {
                provider=it->second;
            }
            else
            {
                provider = std::make_shared<Provider>(c, h);
                _conns.insert(std::make_pair(c, provider));
            }
        }
        // method方法的提供主机要多出一个，_providers新增数据
        _providers[method].insert(provider);
        // 向服务对象中新增一个所能提供的服务名称
        provider->appendMethod(method);
        return provider;
    }
    // 当一个服务提供者断开连接的时候，获取他的信息--用于服务下线通知
    Provider::ptr getProvider(const BaseConnection::ptr &c) {
        std::unique_lock<std::mutex> lock(_mutex);
            auto it = _conns.find(c);
            if (it != _conns.end())
            {
                return it->second;
            }
            return Provider::ptr();
    }
    // 当一个服务提供者断开连接的时候，删除它的关联信息
    void delProvider(const BaseConnection::ptr &c) {
        {
            std::unique_lock<std::mutex> lock(_mutex);
            auto it = _conns.find(c);
            if (it == _conns.end())
            {
                ELOG("无当前服务者的连接");
                return ;
            }
            Provider::ptr provider=it->second;
            std::vector<std::string> methods=provider->methods;
            for(auto &method:methods)
            {
                _providers[method].erase(provider);
            }
            _conns.erase(c);
        }
    }
    std::vector<Address> methodHosts(const std::string &method) {
        std::unique_lock<std::mutex> lock(_mutex);
        auto it = _providers.find(method);
        if (it == _providers.end()) {
            return std::vector<Address>();
        }
        std::vector<Address> result;
        for (auto &provider : it->second) {
            result.push_back(provider->host);
        }
        return result;
    }

private:
    std::mutex _mutex;
    std::unordered_map<std::string, std::set<Provider::ptr>> _providers;
    std::unordered_map<BaseConnection::ptr, Provider::ptr> _conns;
};
class DiscoverManager
{
public:
    using ptr = std::shared_ptr<DiscoverManager>;
    struct Discover
    {
        using ptr = std::shared_ptr<Discover>;
        std::mutex _mutex;
        BaseConnection::ptr conn;         // 发现者关联的客户端连接
        std::vector<std::string> methods; // 发现过的服务名称
        Discover(const BaseConnection::ptr &c) :
        conn(c)
        {}
        void appendMethod(const std::string &method) {
            std::unique_lock<std::mutex> lock(_mutex);
            methods.emplace_back(method);
        }
    };
    // 当每次客户端进行服务发现的时候新增发现者，新增服务名称
    Discover::ptr addDiscover(const BaseConnection::ptr &c,const std::string &method) {
        Discover::ptr discoverer;
        {
            std::unique_lock<std::mutex> lock(_mutex);
            auto it = _conns.find(c);
            if (it != _conns.end()) {
                discoverer = it->second;
            }else {
                discoverer = std::make_shared<Discover>(c);
                _conns.insert(std::make_pair(c, discoverer));
            }
            auto &discoverers = _discoverers[method];
            discoverers.insert(discoverer);
        }
        discoverer->appendMethod(method);
        return discoverer;
    }
    // 发现者客户端断开连接时，找到发现者信息，删除相关数据
    void delDiscover(const BaseConnection::ptr &c) {
        std::unique_lock<std::mutex> lock(_mutex);
        auto it = _conns.find(c);
        if (it == _conns.end()) {
            //没有找到连接对应的发现者信息，代表客户端不是一个服务发现者
            ELOG("没有找到连接对应的发现者信息，代表客户端不是一个服务发现者");
            return;
        }
        for (auto &method : it->second->methods) {
            auto discoverers = _discoverers[method];
            discoverers.erase(it->second);
        }
        _conns.erase(it);
    }
    // 当有一个新的服务提供者上线，则进行上线通知
    void onlineNotify(const std::string &method,const Address &h) {
        notify(method,h,ServiceOptype::SERVICE_ONLINE);
    }
    // 当有一个服务者断开连接，则进行下线通知
    void offlineNotify(const std::string &method,const Address &h) {
        notify(method,h,ServiceOptype::SERVICE_OFFLINE);
    }
private:
    void notify(const std::string &method,const Address &h,const ServiceOptype& soptype)
    {
        std::unique_lock<std::mutex> lock(_mutex);
        auto it=_discoverers.find(method);
        if(it==_discoverers.end())
        {
            ELOG("该服务暂时没有发现者");
            return;
        }
        auto req_msg=MessageFactory::create<ServiceRequest>();
        req_msg->setId(UUID::uuid());
        req_msg->setMethod(method);
        req_msg->setMType(MType::REQ_SERVICE);
        req_msg->setHost(h);
        req_msg->setServiceoptype(soptype);
        for (auto &discoverer : it->second) {
            discoverer->conn->send(req_msg);
        }
    }
private:
    std::mutex _mutex;
    std::unordered_map<std::string, std::set<Discover::ptr>> _discoverers;
    std::unordered_map<BaseConnection::ptr, Discover::ptr> _conns;
};
class PDManager
{
public:
    using ptr = std::shared_ptr<PDManager>;
    PDManager():
    _providers(std::make_shared<ProvideManager>()),
    _discovers(std::make_shared<DiscoverManager>())
    {}
    void onServiceRequest(const BaseConnection::ptr &conn, const ServiceRequest::ptr &msg) {
        //服务操作请求：服务注册/服务发现/
        ServiceOptype optype =msg->Serviceoptype();
        //服务注册：
        //1.新增服务提供者； 2.进行服务上线的通知
        if(optype==ServiceOptype::SERVICE_REGISTER){
        _providers->addProvider(conn,msg->Host(),msg->Method());
        _discovers->onlineNotify(msg->Method(),msg->Host());
        registryResponse(conn,msg);
        }
        else if(optype==ServiceOptype::SERVICE_DISCOVER)
        {
            //服务发现：
            //1.新增服务发现者
            _discovers->addDiscover(conn,msg->Method());
            discoveryResponse(conn,msg);
        }
        else{
            ELOG("收到服务操作请求，但是操作类型错误");
            errorResponse(conn,msg);
        }
        //服务发现：
        //1.新增服务发现者
    }
    void onConnShutdown(const BaseConnection::ptr &conn) {
        auto provider=_providers->getProvider(conn);
        if (provider.get() != nullptr) {
            ILOG("%s:%d 服务下线", provider->host.first.c_str(), provider->host.second);
            for (auto &method : provider->methods) {
                _discovers->offlineNotify(method, provider->host);
            }
            _providers->delProvider(conn);
        }
        _discovers->delDiscover(conn);
    }
private:
void errorResponse(const BaseConnection::ptr &conn, const ServiceRequest::ptr &msg) {
    auto msg_rsp = MessageFactory::create<ServiceResponse>();
    msg_rsp->setId(msg->id());
    msg_rsp->setMType(MType::RSP_SERVICE);
    msg_rsp->setRcode(RCode::RCODE_INVALID_OPTYPE);
    msg_rsp->setOptype(ServiceOptype::SERVICE_UNKOWN);
    conn->send(msg_rsp);
}
void registryResponse(const BaseConnection::ptr &conn, const ServiceRequest::ptr &msg) {
    auto msg_rsp = MessageFactory::create<ServiceResponse>();
    msg_rsp->setId(msg->id());
    msg_rsp->setMType(MType::RSP_SERVICE);
    msg_rsp->setRcode(RCode::RCODE_OK);
    msg_rsp->setOptype(ServiceOptype::SERVICE_REGISTER);
    conn->send(msg_rsp);
}
void discoveryResponse(const BaseConnection::ptr &conn, const ServiceRequest::ptr &msg) {
    auto msg_rsp = MessageFactory::create<ServiceResponse>();
    msg_rsp->setId(msg->id());
    msg_rsp->setMType(MType::RSP_SERVICE);
    msg_rsp->setOptype(ServiceOptype::SERVICE_DISCOVER);
    std::vector<Address> hosts = _providers->methodHosts(msg->Method());
    if (hosts.empty()) {
        msg_rsp->setRcode(RCode::RCODE_NOT_FOUND_SERVICE);
        return conn->send(msg_rsp);
    }   
    msg_rsp->setRcode(RCode::RCODE_OK);
    msg_rsp->setMethod(msg->Method());
    msg_rsp->setHost(hosts);
    return conn->send(msg_rsp);
}
private:
    ProvideManager::ptr _providers;
    DiscoverManager::ptr _discovers;
};
}
}